package br.unisul.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import br.unisul.redeNeural.Configuracao;
import br.unisul.redeNeural.FuncaoAtivacao;
import br.unisul.redeNeural.ParTreino;
import br.unisul.redeNeural.RedeNeural;

public class Ferramentas {
	

	/**
	 * Faz a comparação entre os valores obtidos e as saidas desejadas, retornando um 
	 * String com a comparação entre os resultados
	 * @param obtidos - valores obtidos com o calculo da saida de {@link RedeNeural}
	 * @param saidasDesejadas - saidas desejadas
	 * @return um pequeno relatorio
	 */
	public static String verificarSaida(List<double[]> obtidos, List<double[]> saidasDesejadas){
		int contaAcertos=0, contaErros =0;
		String relatorio = "";
		for (int j = 0; j < obtidos.size(); j++) {
			double[] obtido = obtidos.get(j);
			double[] saidaDesejada = saidasDesejadas.get(j);
			String resposta = "";
			boolean b = Arrays.equals(obtido, saidaDesejada);
			resposta +=  b + ": ";
			resposta +=  Arrays.toString(obtido);
			relatorio += resposta+"\n";
			if(b)
				contaAcertos++;
			else
				contaErros++;
		}
		relatorio+="Acerto :" +contaAcertos;
		relatorio+="\nErros :" +contaErros;
		return relatorio;
	}
	
	/**
	 * Faz a comparacao entre o obtido e o desejado e retorno o seu resultado
	 * @param obtido - valor obtido
	 * @param saidaDesejada - valor desejado
	 * @return um pequeno relatorio
	 */
	public static String verificarSaida(double [] obtido, double[] saidaDesejada){
		String resposta = "";
		boolean b = Arrays.equals(obtido, saidaDesejada);
		resposta +=  b + ": ";
		resposta +=  Arrays.toString(obtido);
		return resposta;
	}
	
	/**
	 * Metodo para aplicar uma determinda função de ativação sobre um vetor de valoes
	 * @param f - funcao de ativacao
	 * @param valores - valores a ser aplicada a função de ativacao
	 * @return vetor de double com os valores retornado da função de ativacaos
	 */
	public static double[] aplicarFuncaoAtivacao(FuncaoAtivacao f, double[] valores){
		double [] temp = new double[valores.length];
		for (int i = 0; i < temp.length; i++) {
			temp[i] = f.funcao(valores[i]);
		}
		return temp;
	}
	/**
	 * Metodo para aplicar uma determinda função de ativação sobre um vetor de valoes
	 * @param f - funcao de ativacao
	 * @param valores - valores a ser aplicada a função de ativacao
	 * @return {@link List} com os valores
	 */
	public static List<double[]> aplicarFuncaoAtivacao(FuncaoAtivacao f, List<double[]> valores){
		List<double[]> temp = new ArrayList<double[]>();
		for (int i = 0; i < valores.size(); i++) {
			temp.add(aplicarFuncaoAtivacao(f, valores.get(i)));
		}
		return temp;
	}
	
	
	/**
	 * Salva uma {@link RedeNeural} em um arquivo
	 * @param redeNeural - {@link RedeNeural} a ser salva
	 * @param arquivo - arquivo onde sera salva
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em salvar a {@link RedeNeural}
	 */
	public synchronized static void salvarRedeNeural(RedeNeural redeNeural, File arquivo) throws Exception{
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(arquivo));
		outputStream.writeObject(redeNeural);
		outputStream.flush();
		outputStream.close();
	}
	
	/**
	 * Faz a leitura do arquivo onde esta salva uma {@link RedeNeural}
	 * @param file - arquivo onde esta salva a {@link RedeNeural}
	 * @return {@link RedeNeural} que esta no arquivo
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em carregar a {@link RedeNeural}
	 */
	public static RedeNeural lerRedeNeural(File file) throws Exception{
		ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));
		RedeNeural n = (RedeNeural) input.readObject();
		input.close();
		return n;
	}
	
	/**
	 * Salva uma {@link Configuracao} em um arquivo
	 * @param configuracao - {@link Configuracao} a ser salva
	 * @param arquivo - arquivo onde sera salva
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em salvar a {@link Configuracao}
	 */
	public synchronized static void salvarConfiguracoes(Configuracao configuracao, File arquivo) throws Exception{
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(arquivo));
		outputStream.writeObject(configuracao);
		outputStream.flush();
		outputStream.close();
	}
	
	/**
	 * Faz a leitura do arquivo onde esta salva uma {@link Configuracao}
	 * @param file - arquivo onde esta salva a {@link Configuracao}
	 * @return {@link Configuracao} que esta no arquivo
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em carregar a {@link Configuracao}
	 */
	public static Configuracao lerConfiguracoes(File file) throws Exception{
		ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));
		Configuracao n = (Configuracao) input.readObject();
		input.close();
		return n;
	}
	
	/**
	 * Salva uma {@link ParTreino} em um arquivo
	 * @param par - {@link ParTreino} a ser salva
	 * @param arquivo - arquivo onde sera salva
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em salvar a {@link ParTreino}
	 */
	public synchronized static void salvarParTreino(ParTreino par, File arquivo) throws Exception{
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(arquivo));
		outputStream.writeObject(par);
		outputStream.flush();
		outputStream.close();
	}
	
	/**
	 * Faz a leitura do arquivo onde esta salva uma {@link ParTreino}
	 * @param file - arquivo onde esta salva a {@link ParTreino}
	 * @return {@link ParTreino} que esta no arquivo
	 * @throws Exception caso ocorra um erro em carregar o arquivo ou em carregar a {@link ParTreino}
	 */
	public static ParTreino lerParTreino(File file) throws Exception{
		ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));
		ParTreino n = (ParTreino) input.readObject();
		input.close();
		return n;
	}
	
}
